/**
 * @author ahammer
 * @date   2010 02
 * @update
 */

/*
 * Fractal Dimension using Higuchi Dimension
 * see T. Higuchi, Physica D 31, 1988, 277
 * and T. Higuchi, Physica D 46, 1990, 254
 * see also  W.Klonowski, E. Olejarczyk, R. Stepien, P. Jalowiecki and R. Rudner, Monitoring The Depth Of Anaesthesia Using Fractal Complexity Method,333-342
 * in:Complexus Mundi: Emergent Patterns In Nature, M.M. Novak ed., World Scientific Publishing, 2006
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tools;
import java.util.Vector;

import main.Board;
import main.IqmTools;

public class Higuchi {

	public Higuchi(){	
	}
	
	/**
	 * This method calculates the "Lengths" of the series
	 * @param data 1D data vector
	 * @param k number of newly calculated time series, k must be smaller than the total number of time points
     *        k should not be greater than N/3 (N number of data points)!
	 * @return Vector L[k] "lengths"
	 */
	public Vector<Double> calcLengths(Vector<Double> data, int k){
		int N = data.size();
		if (k > N){
			k = N/3;
			Board.appendTexln("Higuchi parameter k too large, automatically set to data length/3");
		}
		
		//double[] L = new double[k];
		Vector<Double> L = new Vector<Double>();
		for(int kk = 1; kk <= k; kk++){ 
			double[] Lmk = new double[kk];
			L.add(0.0d);
		    for (int m = 1; m <= kk; m++){
				double norm = (double)(N-1) / (double)((double)(N-m)/(double)kk) / (double) kk / (double) kk;
		    	//double[] TimeSerArr = new double[(N-m)/kk];
		    	//TimeSerArr[0] = data[m-1];
			    int i = 1;
				while (i < (N-m)/kk){   
				    //System.out.println("Higuchi i:" + i +" m:"+ m +" k:"+kk);
			    	//TimeSerArr[i] = data[m-1+i*kk];
			    	Lmk[m-1] += Math.abs(((Double)data.get(m-1+i*kk)).doubleValue() - ((Double)data.get(m-1+(i-1)*kk)).doubleValue()) * norm;
			    	i = i + 1;
				}
				//Lmk[m-1] = FLOAT(TOTAL(ABS(REFORM(TimeSerArr[0:*])-([REFORM(TimeSerArr[0]), REFORM(TimeSerArr[0:*])])))) * FLOAT((N-1)) /FLOAT(FLOAT(N-m)/kk) / FLOAT(kk) /FLOAT(kk)
				L.set(kk-1, ((Double)L.get(kk-1)).doubleValue() + Lmk[m-1]);
		    }
		    //L[kk-1] = FLOAT(TOTAL(Lmk))/ FLOAT(kk)
		    //L[kk-1] = L[kk-1] / (double) kk;
		    L.set(kk-1, ((Double)L.get(kk-1)).doubleValue() /(double) kk);
		}	
		return L;
	}

	
	/**
	 * 
	 * @param L  Higuchi Lengths
	 * @param regStart 
	 * @param regEnd
	 * @return double Dh
	 */
	public double[] calcDimension(Vector<Double> L, int regStart, int regEnd, String plotName, boolean showPlot, boolean deleteExistingPlot){
		//double[] lnDataY = new double[L.size()];
		//double[] lnDataX = new double[L.size()];  //k
		Vector<Double> lnDataY = new Vector<Double>();
		Vector<Double> lnDataX = new Vector<Double>();  //k
		for (int i = 0; i < L.size(); i++){
			if ((Double)L.get(i) == 0) L.set(i, Double.MIN_VALUE);
		}
		for (int i = 0; i < L.size(); i++){
			lnDataX.add(Math.log(i+1));
			lnDataY.add(Math.log(((Double)L.get(i)).doubleValue()));
		}
		double[] p = IqmTools.getLinearRegression(lnDataX, lnDataY, regStart, regEnd);
		
		if (showPlot) {
			boolean isLineVisible = false;
			IqmTools.displayRegressionPlotXY(lnDataX, lnDataY, isLineVisible, plotName, "Higuchi Dimension", "ln(k)", "ln(L)", regStart, regEnd, deleteExistingPlot);
		}				
		double[] out = {p[1], p[3], p[4], p[5]};  //-slope = Dh, standard deviation, r2 , adjusted r2  
		return out;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	
	}

}
